import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from python_ai.common.xcommon import sep

# show all data when printing
pd.set_option('display.max_rows', None, 'display.max_columns', None, 'display.max_colwidth', 1000, 'display.expand_frame_repr', False)

# 读取数据
df = pd.read_csv(r'../../../../../large_data/ML2/共享单车/train.csv')
m = len(df)
# columns:
# datetime  season  holiday  workingday  weather  temp   atemp  humidity  windspeed  casual  registered  count
# atemp 体感温度？
# casual 未注册用户租赁数
# registered 注册用户租赁数
# count = casual + registered

# 将datetime列，切分出年月日时   YYYY-MM-DD HH:mm:ss
df['date'] = df.apply(lambda x: x['datetime'].split(' ')[0], axis=1)
df['Y'] = df.datetime.apply(lambda x: int(x.split(' ')[0].split('-')[0], 10))
df['M'] = df.datetime.apply(lambda x: int(x.split(' ')[0].split('-')[1], 10))
df['D'] = df.datetime.apply(lambda x: int(x.split(' ')[0].split('-')[2], 10))
df['H'] = df.datetime.apply(lambda x: int(x.split(' ')[1].split(':')[0], 10))
import calendar
import datetime
df['month'] = df.M.apply(lambda x: calendar.month_name[x])
df['weekday'] = df.date.apply(
    lambda x: calendar.day_name[datetime.datetime.strptime(x, '%Y-%m-%d').weekday()]
)

# figure group
plt.figure(figsize=[16, 8])
spr = 2
spc = 4
spn = 0

# 按照小时，统计用车数量
sep('H')
h_cnt = df.groupby('H').agg(np.sum)['count']
print(h_cnt)
print(type(h_cnt), h_cnt.shape, h_cnt.name, h_cnt.index.name)  # ATTENTION Name of Series ('count') and name of Series' index ('H')
h_cnt_rsi = h_cnt.reset_index()  # ATTENTION columns = ('H', 'count')
print(type(h_cnt_rsi), h_cnt_rsi.shape, h_cnt_rsi.columns, h_cnt_rsi.index)
spn += 1
plt.subplot(spr, spc, spn)
sns.barplot(data=h_cnt_rsi, x='H', y='count')
spn += 1
plt.subplot(spr, spc, spn)
plt.title('Seaborn directly on df')
sns.barplot(data=df, x='H', y='count',
            estimator=np.sum,  # ATTENTION Agg sum
            ci=None,  # ATTENTION No error bar.
            )
spn += 1
plt.subplot(spr, spc, spn)
h_cnt.plot(kind='bar')
spn += 1
plt.subplot(spr, spc, spn)
h_cnt.plot(kind='line')


# 最终按照上班高峰，下班高峰，白天低谷，晚上低谷，分成四个小时段
# Teacher => 5组
def h_section(h):
    if h <= 6:
        return 0
    elif h <= 10:
        return 1
    elif h <= 15:
        return 2
    elif h <= 20:
        return 3
    else:
        return 4


df['h_section'] = df['H'].map(h_section)
print(df[:5])
h_section_cnt = df.groupby('h_section').agg(np.sum)['count'].reset_index()
spn += 1
plt.subplot(spr, spc, spn)
sns.barplot(data=h_section_cnt, x='h_section', y='count')

# 将count中的噪音值用箱线图进行显示
spn += 1
plt.subplot(spr, spc, spn)
sns.boxplot(data=df, y='count')
spn += 1
plt.subplot(spr, spc, spn)
sns.boxplot(data=df, x='count')

# 显示非噪音数据的比例
# abs(x - mean) >= 3*std   噪音
# abs(x - mean) # 绝对值
mu = df['count'].mean()
sigma = df['count'].std()
idx_bad_np = abs(df['count'] - mu) >= 3 * sigma
bad_rate = sum(idx_bad_np) / len(idx_bad_np)
print(f'noise rate: {bad_rate}')

# 删除噪音数据（保留非噪音数据）
idx_good_np = np.invert(idx_bad_np)
df = df[idx_good_np].copy()

# ③	从数据中获取'temp', 'atemp', 'hum', 'windspeed'列作为特征（5分）
x = df.loc[:, ['temp', 'atemp', 'humidity', 'windspeed']]
print(x[:5])

# ④	从数据中获取'cnt'作为标签值（5分）
y = df['count']

# ⑤	对特征求皮尔逊系数（5分）
xcorr = x.corr()
print(xcorr)

# ⑥	使用皮尔逊系数绘制热图（5分）
sep('⑥	使用皮尔逊系数绘制热图（5分）')
spn += 1
plt.subplot(spr, spc, spn)
ax = sns.heatmap(data=xcorr, annot=True)
top, bottom = ax.get_ylim()  # ATTENTION fix heatmap
ax.set_ylim([top + 0.5, bottom - 0.5])

# ⑦	将皮尔逊系数大于1特征进行处理（删除1项）（5分）
xone = False
for i, idx in enumerate(xcorr.index):
    if xone:
        break
    for j, col in enumerate(xcorr.iloc[i].index):
        if xone:
            break
        if j <= i:
            continue
        val = xcorr.iloc[i, j]
        if float(val) > 0.6:
            del x[x.columns[j]]
            xone = True

print(x[:5])

# ⑧	使用留出法切分数据，比例7:3（5分）
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.7, random_state=666)

# (2)	模型处理及评估（35分）

# ①	创建管道，内部填写后续三项内容（5分）
# ②	管道中先进行多项式处理，使用3次方（5分）
# ③	管道中进行标准化处理（5分）
# ④	管道中使用线性回归（5分）
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures, StandardScaler  # ATTENTION PolynomialFeatures is in preprocessing
from sklearn.linear_model import LinearRegression
pipe = Pipeline([
    ['poly', PolynomialFeatures(degree=3)],  # ATTENTION degree
    ['std', StandardScaler()],
    ['lin_reg', LinearRegression()]
])
# ⑤	拟合训练集数据（5分）
pipe.fit(x_train, y_train)

# ⑥	打印预测值（5分）
h_train = pipe.predict(x_train)
h_test = pipe.predict(x_test)

# ⑦	打印输出模型的均方误差（5分）
from sklearn.metrics import mean_squared_error, r2_score
print(f'Train均方误差:{mean_squared_error(y_train, h_train)}')
print(f'Test均方误差:{mean_squared_error(y_test, h_test)}')
print(f'Train R2:{r2_score(y_train, h_train)}')
print(f'Test R2:{r2_score(y_test, h_test)}')

# show all drawingss
plt.show()
